package com.application.race.manage.player;

import java.util.ArrayList;
import java.util.List;

import org.apache.mina.core.buffer.IoBuffer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.application.item.pojo.Item;
import com.application.race.manage.DEF;
import com.application.race.manage.RacingRoom;
import com.application.race.manage.misc.RacingItem;
import com.application.race.manage.player.effect.BlastEffect;
import com.application.race.manage.player.effect.CaroticEffect;
import com.application.race.manage.player.effect.CrashEffect;
import com.application.race.manage.player.effect.Effect;
import com.application.race.manage.player.effect.EffectChecker;
import com.application.race.manage.player.effect.RemoveEffect;
import com.application.race.manage.player.effect.skill.RepairEffect;
import com.application.race.manage.player.effect.skill.StrickEffect;
import com.core.action.ActionConstants;
import com.core.utils.GameUtils;
import com.core.utils.PushDataUtils;

public class CrashChecker {
	
	private static final Logger log = LoggerFactory
	.getLogger(CrashChecker.class);		

	 
	private RacingRoom room;
	public EffectChecker eftCheck;
    private List<Player> players=new ArrayList<Player>();
	public CrashChecker(RacingRoom room, EffectChecker ec) {
		for(Player p:room.players.values())
			players.add(p);
		this.room = room;
		eftCheck = ec;
	}

	boolean hasConflict = false;
	public Effect eft;
	Long temp;
	long time;
    List<Player> crashList=new ArrayList<Player>();
    int mm,nn;
    Player player1, player2;
	public void checkConflict() {

		hasConflict = false;
		if(crashList.size()>0)crashList.clear();
		// conflictTable=new Array;
	
		for (mm=0;mm<players.size();mm++) {
			player1 = players.get(mm);
			if (!player1.crashEnable())
				continue;
			time = System.currentTimeMillis();
			checkItemCrash(player1);
			for (nn=mm+1;nn<players.size();nn++) {
				player2 = players.get(nn);
				if (!player2.crashEnable())
					continue;
				checkOneConflict(player1, player2);
			}
			if (player1.hadCrash) {
				System.out.println("onframe");
//				synchronized (room.actions) {
//					room.actions.addCrashAction(player1);
//					// if()
//				}
				crashList.add(player1);
				player1.dec_blood = 0;
				player1.hadCrash = false;
			}
		}
		if(crashList.size()<=0)return;
		System.out.println("crash ");
//		try{
//			Thread.sleep(100);
//		}catch(Exception e){}
		IoBuffer sendBuffer = IoBuffer.allocate(128);
		sendBuffer.setAutoExpand(true);
		sendBuffer.putInt(ActionConstants.S2C_ACTION_RACE_ACTION_HEADER);
		sendBuffer.put(ActionConstants.RACE_ACTION_CRASH);
		sendBuffer.put((byte)crashList.size());
    	for(Player p:crashList){
    		p.actionId++;
    		sendBuffer.putInt(p.actor.getId());
    		sendBuffer.putShort((short)p._x);
    		sendBuffer.putShort((short)p._y);
    		//System.out.println(p._dvx);
    		sendBuffer.putDouble(p._dvx);
    		sendBuffer.putDouble(p._dvy);
    		
    		sendBuffer.putInt(p.action.getCurentActionCode());
        	sendBuffer.putInt(p.actionId);
    	}
		
		
 		if(eft!=null){
 
//			sendBuffer.putInt(ActionConstants.S2C_ACTION_RACE_ACTION_HEADER);
//			sendBuffer.put(ActionConstants.RACE_ACTION_EFFECT);
//			sendBuffer.put(eft.effectType);
//	    	
//	    	switch(eft.effectType){
//			 	case Effect.EFFECT_TYPE_UNDER_ATK:
//			 	case Effect.EFFECT_TYPE_UNDER_FATAL_ATK_L1:
//			 	case Effect.EFFECT_TYPE_UNDER_FATAL_ATK_L2:
//			 	case Effect.EFFECT_TYPE_UNDER_FATAL_ATK_L3:
//			 		sendBuffer.putInt(eft.receiver);
//			 		sendBuffer.putInt(eft.initiator);
//			 		sendBuffer.putInt(((CrashEffect) eft).nowBlood);
//			 		sendBuffer.putInt(((CrashEffect) eft).absBlood);
//			 		break;
//			 	case Effect.EFFECT_TYPE_CAROTIC:
//			 		sendBuffer.putInt(eft.receiver);
//			 		sendBuffer.putInt(eft.initiator);
//			 		sendBuffer.putInt(eft.effectId);
//			 		sendBuffer.putInt(((CaroticEffect) eft).maxTime);
//		    		break;
//			 	case Effect.EFFECT_TYPE_REPAIR:
//			 		sendBuffer.putInt(eft.receiver);
//			 		sendBuffer.putInt(eft.initiator);
//			 		sendBuffer.putInt(((RepairEffect) eft).nowBlood);
//			 		sendBuffer.putInt(((RepairEffect) eft).addBlood);
//		    		break;
//			 	case Effect.EFFECT_TYPE_REMOVE:
//			 		sendBuffer.putInt(((RemoveEffect) eft).removeType);
//			 		sendBuffer.putInt(((RemoveEffect) eft).removeId);
//			 		break;
//			 	case Effect.EFFECT_TYPE_BLAST:
//			 		sendBuffer.putInt(eft.receiver);
//			 		sendBuffer.putInt(((BlastEffect) eft).nowBlood);
//			 		sendBuffer.putInt(((BlastEffect) eft).absBlood);
//			 		break;
//			 	case Effect.EFFECT_TYPE_FOCUS:
//			 	case Effect.EFFECT_TYPE_DODGE:
//			 	case Effect.EFFECT_TYPE_RESIST:
//			 	case Effect.EFFECT_TYPE_JUMP:
//			 	case Effect.EFFECT_TYPE_HIDE:
//			 		sendBuffer.putInt(eft.receiver);
//			 		sendBuffer.putInt(eft.initiator);
//			 		break;
//			 	case Effect.EFFECT_TYPE_STRICK:
//			 		sendBuffer.putInt(eft.receiver);
//			 		sendBuffer.putInt(eft.initiator);
//			 		sendBuffer.putInt(eft.actionid);
//			 		sendBuffer.putShort((short)((StrickEffect)eft).x);
//			 		sendBuffer.putShort((short)((StrickEffect)eft).y);
//			 		sendBuffer.putInt(((StrickEffect)eft).ang);
//			 		break;
//	    	}
//		 
// 
//		eft = null;
	 
		}
 		sendBuffer.flip();
		sendBuffer = GameUtils.Serialize(sendBuffer);
		PushDataUtils.fastPush(sendBuffer, room.actors,
				ActionConstants.S2C_ACTION_RACE_ACTION_HEADER);

	}
	RacingItem ri ;
	private void checkItemCrash( Player p){
		for(int i=0;i<room.items.size();i++){
			ri=room.items.get(i);
			if(ri.owner==p){
				if(room.currentTime- ri.ceateTime<2500){
					return;
				}
			}
			if(!ri.valid)return;
			abs_x = ri.x - p._x;
			abs_y = ri.y - p._y;	
			if(Math.abs(abs_x) > (p.carInfo.confRadius+10) )continue;
		    if(Math.abs(abs_y) > (p.carInfo.confRadius+10) )continue;
		    ri.valid=false;
			RemoveEffect rc = new RemoveEffect();
			rc.removeId = ri.racingItemid;
			rc.removeType=1;//remove an  item  effect
			room.actions.addEffect(rc);
			checkItemCrashEffect(p,ri);
		}


	}
    private void checkItemCrashEffect(Player p,RacingItem ri){
    	Item bi=ri.item;
    	switch(bi.itemId){
    	    case 11050:
    	    	p.up_speed=0;
    	    	p.down_speed=0;
    	    	p.resetAction();
    	    	int decbld=(int)(DEF.random(20,40)/100.0*p.max_blood)-DEF.random(p.carInfo.mindef, p.carInfo.maxdef)*3;
    	    	if(decbld<40)decbld=DEF.random(30,50);
    	    	if(decbld>p.now_blood)decbld=p.now_blood;
    	    	p.now_blood-=decbld;
    	    	if(p.now_blood<=0)p.dead=true;
    	    	if(ri.owner!=p){
    	    		ri.owner.totalDamage+=decbld;
    	    	}
    			BlastEffect bla=new BlastEffect();
    			bla.receiver=p.actor.getId();
    			bla.nowBlood = p.now_blood;
    			bla.absBlood = decbld;
    			this.room.actions.addEffect(bla);
    
    	    	break;
    	}
    }
	double abs_x, abs_y, abs_total_0, abs_total_1, distance, distance_next,
			totalRadius;

	public void checkOneConflict(Player actorContrl, Player actor) {
		totalRadius = actorContrl.carInfo.confRadius + actor.carInfo.confRadius;
		// if(hasConflict)return;

		// totalRadius=60;
		abs_x = actorContrl._x - actor._x;
		abs_y = actorContrl._y - actor._y;
		if (Math.abs(abs_x) > totalRadius || Math.abs(abs_y) > totalRadius)
			return;

		abs_x = abs_x * abs_x;
		abs_y = abs_y * abs_y;
		distance = Math.sqrt(abs_x + abs_y);

		if (totalRadius > distance) {

			abs_x = actorContrl._x + actorContrl._vx
					+ actorContrl.sideClipContrl.tx
					- (actor._x + actor._vx + actor.sideClipContrl.tx);
			abs_y = actorContrl._y + actorContrl._vy
					+ actorContrl.sideClipContrl.ty
					- (actor._y + actor._vy + actor.sideClipContrl.ty);
			abs_x = abs_x * abs_x;
			abs_y = abs_y * abs_y;
			distance_next = Math.sqrt(abs_x + abs_y);

			if (distance_next < distance) {
				hasConflict = true;
				makeConflictEffect(actorContrl, actor);
			}

		}
	}

	long crashTime;
	boolean initiative1 = false;
	boolean initiative2 = false;
	static double w1 = 1.3;
	static double w2 = 0.3;
	static double po1 = 0.2;
	double po, abs1, abs2, double1, dx, dy, sin, cos, crash_angle, ang1, ang2,
			_ang1, _ang2, r1, r2, a1, a2, dx1, dy1, sideClip_dx1, sideClip_dy1,
			sideClip_dx2, sideClip_dy2;

	private void makeConflictEffect(Player car1, Player car2) {

		dx = car1._x - car2._x;
		dy = car1._y - car2._y;

		crash_angle = Math.atan2(dy, dx);


		int convertedAng1 = convertAngToRealConfAng(radiouToAngle(crash_angle));
		// log.info(car2._userName+"  at "+car1._userName+"   "+convertedAng1);
		int convertedAng2;
		if (convertedAng1 > 180) {
			convertedAng2 = convertedAng1 - 180;
		} else {
			convertedAng2 = 180 + convertedAng1;
		}
		// log.info(car1._userName+"  at "+car2._userName+"   "+convertedAng2);

		int con1 = convertedAng1 - car1._angle;
		if (con1 < 0)
			con1 += 360;
		int con2 = convertedAng2 - car2._angle;
		if (con2 < 0)
			con2 += 360;
		cacuCrashPart(car1, con1);
		cacuCrashPart(car2, con2);
		ang1 = Math.atan2(car1._vy, car1._vx);
		ang2 = Math.atan2(car2._vy, car2._vx);
		_ang1 = 2 * crash_angle - ang1 - Math.PI;
		_ang2 = 2 * crash_angle - ang2 - Math.PI;

		r1 = Math.sqrt(car1._vx * car1._vx + car1._vy * car1._vy);
		r2 = Math.sqrt(car2._vx * car2._vx + car2._vy * car2._vy);
		a1 = r1 * Math.cos(crash_angle - ang1);
		a2 = r2 * Math.cos(crash_angle - ang2);
		abs1 = Math.abs(a1);
		abs2 = Math.abs(a2);
		initiative1 = false;
		initiative2 = false;
		if (abs2 > abs1)
			initiative2 = true;
		if (abs1 > abs2)
			initiative1 = true;
		if(room.mode==0 ||( room.mode==1 && car1.teamId!=car2.teamId)){
			makeCrashEffect(car1, abs1, car2, initiative1);
			makeCrashEffect(car2, abs2, car1, initiative2);
		}
		crashTime = System.currentTimeMillis();
		dx1 = a1 * Math.cos(crash_angle) + a2 * Math.cos(crash_angle);
		dy1 = a1 * Math.sin(crash_angle) + a2 * Math.sin(crash_angle);

		sideClip_dx1 = r1 * Math.cos(_ang1) + dx1;
		sideClip_dy1 = r1 * Math.sin(_ang1) + dy1;
		sideClip_dx2 = r2 * Math.cos(_ang2) + dx1;
		sideClip_dy2 = r2 * Math.sin(_ang2) + dy1;

		double1 = car1.weight / car2.weight;
		if (double1 > w1)
			double1 = w1;
		if (double1 < w2)
			double1 = w2;
		car2._dvx = sideClip_dx2 * double1;
		car2._dvy = sideClip_dy2 * double1;
		po = Math.abs(car2._dvx) + Math.abs(car2._dvy);
		if (po != 0) {
			if (po < po1) {
				car2._dvx = car2._dvx * (po1 / po);
				car2._dvy = car2._dvy * (po1 / po);
			}
		}

		car2.sideClipContrl.addCrash(car2._dvx, car2._dvy);
		// car2.crashTable.put(car1._userName,crashTime);

		double1 = car2.weight / car1.weight;
		if (double1 > w1)
			double1 = w1;
		if (double1 < w2)
			double1 = w2;
		car1._dvx = sideClip_dx1 * double1;
		car1._dvy = sideClip_dy1 * double1;
		po = Math.abs(car1._dvx) + Math.abs(car1._dvy);

		if (po != 0) {
			if (po < po1) {
				car1._dvx = car1._dvx * (po1 / po);
				car1._dvy = car1._dvy * (po1 / po);
			}
		}
		car1.sideClipContrl.addCrash(car1._dvx, car1._dvy);
		// car1.crashTable.put(car2._userName,crashTime);

		car2.hadCrash = true;
		car1.hadCrash = true;
		// log.info(car1._x+ " crash  "+car2._x+" "+car1._y+
		// "   "+car2._y);

	}

	private void makeCrashEffect(Player car1, double power, Player car2,
			boolean initiative) {
		if (power < po1)
			return;
		// log.info("..........makeCrashEffect ");
		eft = eftCheck.checkCrash(car1, power, car2, initiative);

	}

	double ret;

	double radiouToAngle(double radiou) {
		ret = radiou / (Math.PI * 2) * 360;
		return ret;
	}

	int convertAngToRealConfAng(double a) {
		int ang = (int) a;

		if (ang > 0)
			ang -= 90;
		else if (ang < 0)
			ang = 90 + 180 + ang;
		if (ang < 0)
			ang += 360;
		return ang;
	}

	public static int CRASH_PART_HEAD = 0;
	public static int CRASH_PART_FRONT = 1;
	public static int CRASH_PART_BODY = 2;
	public static int CRASH_PART_BACK = 3;
	public static int CRASH_PART_TAIL = 4;

	public void cacuCrashPart(Player car, int ang) {
		if(ang>180)ang=360-ang;
		if (ang<50)
			car.crashPart = CRASH_PART_HEAD;
		else if (ang < 80)
			car.crashPart = CRASH_PART_FRONT;
		else if (ang < 110)
			car.crashPart = CRASH_PART_BODY;
		else if (ang < 140)
			car.crashPart = CRASH_PART_BACK;
		else
			car.crashPart = CRASH_PART_TAIL;

		//log.info(car._userName + "    " + car.crashPart);
	}
	// public void makeCaroticStus(PlayerInfo car1,PlayerInfo car2){
	// if(rand.nextInt(100)<50)
	// car1.status=car1.status|1;
	// }

}
